package org.tjc.net.manager.config.json;

import com.alibaba.fastjson.JSON;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import sun.security.krb5.Config;

import java.io.*;
import java.util.*;

/**
 * @Author: tjc
 * @description
 * @Date Created in 17:38 2020-12-12
 */
public class Configuration {

    private Object root;

    private Configuration(String json) {
        try {
            this.root = JSON.parse(json);
        } catch (Exception e) {
            throw new RuntimeException("配置信息错误. 您提供的配置信息不是合法的JSON格式: %s . 请按照标准json格式提供配置信息. ", e);
        }
    }


    public List<Object> getList(final String path) {
        List<Object> list = this.get(path, List.class);
        if (list == null) {
            return null;
        }
        return list;
    }

    public <T> T get(final String path, Class<T> clazz) {
        this.checkPath(path);
        return (T) this.get(path);
    }

    public <T> List<T> getList(final String path, Class<T> t) {
        Object object = this.get(path, List.class);
        if (null == object) {
            return null;
        }
        List<T> result = new ArrayList<T>();

        List<Object> origin = (List<Object>) object;
        for (final Object each : origin) {
            result.add((T) each);
        }

        return result;
    }


    public Object get(final String path) {
        this.checkPath(path);
        try {
            return this.findObject(path);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 功能描述: 获取子集
     *
     * @Author: tjc
     * @Date: 2020-12-21 21:51
     */
    public Configuration getConfiguration(final String path) {
        Object object = this.get(path);
        if (null == object) {
            return null;
        }

        return Configuration.from(Configuration.toJSONString(object));
    }



    private static Configuration from(String json) {

        try {
            return new Configuration(json);
        } catch (Exception e) {
            throw new RuntimeException("获取configuration子集失败");
        }
    }

    public static Configuration from(final Map<String, Object> object) {
        return Configuration.from(Configuration.toJSONString(object));
    }


    /**
     * 从List对象加载Configuration
     */
    public static Configuration from(final List<Object> object) {
        return Configuration.from(Configuration.toJSONString(object));
    }

    public static Configuration from(final Object object) {
        return Configuration.from(Configuration.toJSONString(object));
    }

    public static Configuration from(File file) {
        try {
            return Configuration.from(IOUtils
                    .toString(new FileInputStream(file)));
        } catch (FileNotFoundException e) {
            throw new RuntimeException("配置信息错误. 您提供配置文件失败");
        } catch (IOException e) {
            throw new RuntimeException("配置信息错误. 您提供配置文件失败");
        }
    }


    private static String toJSONString(Object object) {
        return JSON.toJSONString(object);
    }

    private void checkPath(String path) {
        if (null == path) {
            throw new IllegalArgumentException(
                    "系统编程错误, 该异常代表系统编程错误!.");
        }

        for (final String each : StringUtils.split(".")) {
            if (StringUtils.isBlank(each)) {
                throw new IllegalArgumentException(String.format(
                        "系统编程错误, 路径[%s]不合法, 路径层次之间不能出现空白字符 .", path));
            }
        }
    }


    private List<String> split2List(String path) {
        return Arrays.asList(StringUtils.split(split(path), "."));
    }

    private String split(final String path) {
        return StringUtils.replace(path, "[", ".[");
    }

    private Object findObject(final String path) {
        boolean isRootQuery = StringUtils.isBlank(path);
        if (isRootQuery) {
            return this.root;
        }
        Object target = this.root;
        for (final String each : split2List(path)) {
            if (isPathMap(each)) {
                target = findObjectInMap(target, each);
                continue;
            } else {
                target = findObjectInList(target, each);
                continue;
            }
        }

        return target;
    }

    @SuppressWarnings("unchecked")
    private Object findObjectInMap(final Object target, final String index) {
        boolean isMap = (target instanceof Map);
        if (!isMap) {
            throw new IllegalArgumentException(String.format(
                    "您提供的配置文件有误. 路径[%s]需要配置Json格式的Map对象，但该节点发现实际类型是[%s]. 请检查您的配置并作出修改.",
                    index, target.getClass().toString()));
        }

        Object result = ((Map<String, Object>) target).get(index);
        if (null == result) {
            throw new IllegalArgumentException(String.format(
                    "您提供的配置文件有误. 路径[%s]值为null，ng无法识别该配置. 请检查您的配置并作出修改.", index));
        }

        return result;
    }

    @SuppressWarnings({"unchecked"})
    private Object findObjectInList(final Object target, final String each) {
        boolean isList = (target instanceof List);
        if (!isList) {
            throw new IllegalArgumentException(String.format(
                    "您提供的配置文件有误. 路径[%s]需要配置Json格式的Map对象，但该节点发现实际类型是[%s]. 请检查您的配置并作出修改.",
                    each, target.getClass().toString()));
        }

        String index = each.replace("[", "").replace("]", "");
        if (!StringUtils.isNumeric(index)) {
            throw new IllegalArgumentException(
                    String.format(
                            "系统编程错误，列表下标必须为数字类型，但该节点发现实际类型是[%s] ，该异常代表系统编程错误, 请联系net-manager开发团队 !",
                            index));
        }

        return ((List<Object>) target).get(Integer.valueOf(index));
    }

    public List<Configuration> getListConfiguration(final String path) {
        List<Object> lists = getList(path);
        if (lists == null) {
            return null;
        }

        List<Configuration> result = new ArrayList<Configuration>();
        for (final Object object : lists) {
            result.add(Configuration.from(Configuration.toJSONString(object)));
        }
        return result;
    }


    private boolean isPathMap(final String path) {
        return StringUtils.isNotBlank(path) && !isPathList(path);
    }

    private boolean isPathList(final String path) {
        return path.contains("[") && path.contains("]");
    }

    public static void main(String[] args) {
        Configuration configuration = new Configuration("/home/tjc/code/net-manager/net-manager.json");
        Object o = configuration.findObject("http.server[0].port");
        System.out.println(o);
    }

    public Set<String> getKeys() {
        Object current = this.getInternal();
        Set<String> collect = new HashSet<String>();

        boolean isMap = current instanceof Map;
        if (isMap) {
            Map<String, Object> mapping = ((Map<String, Object>) current);
            for (final String key : mapping.keySet()) {
                collect.add(key);
            }
        }

        //todo 这里不完善

        return collect;
    }

    public Object getInternal() {
        return this.root;
    }
}
